///////////////////////////////////////////////////////////////////////////////
//
// Licensed under the MIT License
//
// Copyright (c) 2010 Chris Colinsky
// All Rights Reserved
//
// version	0.5
// http://code.google.com/p/sugarcookie/
// http://code.google.com/p/sugarcookie/wiki/License
//
////////////////////////////////////////////////////////////////////////////////

package sugarcookie.media {
	import flash.display.Sprite;
	import flash.events.ActivityEvent;
	import flash.events.AsyncErrorEvent;
	import flash.events.IOErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.StatusEvent;
	import flash.media.Camera;
	import flash.media.Microphone;
	import flash.media.SoundCodec;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.utils.ObjectUtil;
	
	import sugarcookie.error.ApplicationError;
	
	public class UICamera extends Sprite {
		private var _log:ILogger;
		private var _cam:Camera;
		private var _mic:Microphone;
		private var _vid:Video;
		
		private var _conn:NetConnection;
		private var _ns:NetStream;
		
		private var _fps:uint;
		private var _captureWidth:Number;
		private var _captureHeight:Number;
		private var _livePreviewWidth:Number;
		private var _livePreviewHeight:Number;
		private var _hasAudio:Boolean;
		private var _inst:String;
		private var _pubType:String;
		
		public function UICamera(captureWidth:Number=160,captureHeight:Number=120,fps:uint=24,withAudio:Boolean=true) {
			super();
			
			_log = Log.getLogger("sugarcookie.media.UICamera");
			_livePreviewWidth = _captureWidth = captureWidth;
			_livePreviewHeight = _captureHeight = captureHeight;
			_fps = fps;
			_hasAudio = withAudio;
			
			initCamera();
		}
		
		public function initPublish(application:String,instanceName:String,type:String):void {
			_log.debug("init publish");
			_inst = instanceName;
			_pubType = type;
			
			_conn = new NetConnection();
			_conn.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
            _conn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError);
			_conn.addEventListener(IOErrorEvent.IO_ERROR, ioError);
			_conn.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncError);
			_conn.connect(application);
		}
		
		public function start(instanceName:String=null,type:String=null):void {
			if (instanceName==null && type==null) _pubType = "append";
			if (instanceName!=null) _inst = instanceName;
			if (type!=null) _pubType = type;
			_ns.publish(_inst, _pubType);
		}
		
		public function stop():void {
			_ns.close();
		}
		
		public function injectLiveData(metadata:Object):void {
			_log.debug("Injecting data into live stream: "+ObjectUtil.toString(metadata));
			_ns.send("@setDataFrame", "onMetaData", metadata);
		}
		
		public function setDisplayDimensions(width:Number,height:Number):void {
			_livePreviewWidth = width;
			_livePreviewHeight = height;
			if (_vid) {
				_vid.width = _livePreviewWidth;
				_vid.height = _livePreviewHeight;
			}
		}
		
		public function setCamera(id:Object):void {
			/*if (isNaN(id)) {
				var names:Array = Camera.names;
				
			} else {
				
			}*/
		}
		
		private function initCamera():void {
			_cam = Camera.getCamera();
			if (!_cam) throw new ApplicationError("Camera not found.  Please check your connections and ensure that your camera is not in use by another application.");
			
			_cam.setMode(_captureWidth, _captureHeight, _fps);
			_cam.setQuality(0,60);
			_cam.addEventListener(ActivityEvent.ACTIVITY, camActivity);
			_cam.addEventListener(StatusEvent.STATUS, camStatus);
			_log.debug("Initing camera: "+ _cam.name);
			
			if (_hasAudio) initMicrophone();
			initDisplay();
		}
		
		private function initMicrophone():void {
			_mic = Microphone.getMicrophone(2);
			if (!_mic) throw new ApplicationError("Microphone not found.  Please check your connections and ensure that your mmicropone is not in use by another application.");
			
			_mic.codec = SoundCodec.SPEEX;
			_mic.encodeQuality = 6;
			_mic.gain = 0;
			_mic.rate = 16;
			_mic.setSilenceLevel(10,30000);
		}
		
		private function initDisplay():void {
			_vid = new Video(_livePreviewWidth,_livePreviewHeight);
			_vid.attachCamera(_cam);
			addChild(_vid);
		}
		
		private function connectStream():void {
			_ns = new NetStream(_conn);
            _ns.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
            _ns.client = this;
            _ns.attachCamera(_cam); 
    		_ns.attachAudio(_mic);
    		start(_inst,_pubType);
		}
		
		private function camActivity(evt:ActivityEvent):void {
			_log.debug("event: " + evt);
		}
		
		private function camStatus(evt:StatusEvent):void {
			_log.debug("event: " + evt);
		}
		
		private function netStatus(evt:NetStatusEvent):void {
			_log.debug("net status: " + ObjectUtil.toString(evt.info));
			switch (evt.info.code) {
                case "NetConnection.Connect.Success":
                    connectStream();
                    break;
                case "NetStream.Publish.Start":
                	break;
            }
		}
		
		private function securityError(evt:SecurityErrorEvent):void {
			_log.debug("security error: " + evt);
		}
		
		private function ioError(evt:IOErrorEvent):void {
			_log.debug("io error: " + evt);
		}
		
		private function asyncError(evt:AsyncErrorEvent):void {
			_log.debug("async error: " + evt);
		}
		
		public function onPlayStatus(info:Object):void {
	        _log.debug("playStatus: "+ObjectUtil.toString(info));
	    }
        
        public function onMetaData(info:Object):void {
	        _log.debug("metaData: "+ObjectUtil.toString(info));
	    }
	    
	    public function onCuePoint(info:Object):void {
	        _log.debug("cuePoint: "+ObjectUtil.toString(info));
	    }
	}
}